/**
 * FIFOFixTimeQueue.java
 */
package com.mht2017.common.dto;

import java.util.ArrayDeque;

import com.mht2017.common.utils.SizeUtil;

/**
 * 存放指定时间的队列，超过时间的数字将被移除<br/>
 * 移除规则：仅当有新元素加入或者读取数字的时候才触发移除算法
 *
 * @author yutong.xiao
 * @date 2017年3月30日 下午1:38:04
 */
public class FIFOFixTimeQueue {

	private final long fixTimeDelta;
	private final ArrayDeque<Pair> deque;

	public FIFOFixTimeQueue(long fixTimeDeltaInMills) {
		fixTimeDelta = fixTimeDeltaInMills;
		deque = new ArrayDeque<>();
	}

	public synchronized void add(long e) {
		check();
		deque.addLast(new Pair(e, System.currentTimeMillis()));
	}

	private void check() {
		long now = System.currentTimeMillis();
		while (deque.isEmpty() == false) {
			if (now - deque.getFirst().timestamp > fixTimeDelta) {
				deque.removeFirst();
			} else {
				break;
			}
		}
	}

	public synchronized long[] getAllElements() {
		check();
		Pair[] array = deque.toArray(new Pair[deque.size()]);
		long[] results = new long[SizeUtil.sizeZeroIfNull(array)];
		if (SizeUtil.isNotEmpty(array)) {
			for (int i = 0; i < array.length; i++) {
				results[i] = array[i].data;
			}
		}
		return results;
	}

	public double avg() {
		long[] all = getAllElements();
		if (null == all) {
			return 0;
		}

		int sum = 0;
		for (long data : all) {
			sum += data;
		}
		return 1D * sum / all.length;
	}

	public long sum() {
		long[] all = getAllElements();
		if (null == all) {
			return 0;
		}

		long sum = 0;
		for (long data : all) {
			sum += data;
		}
		return sum;
	}

	public int getActualSize() {
		check();
		return deque.size();
	}

	public long getFixTimeDelat() {
		check();
		return fixTimeDelta;
	}

	@Override
	public String toString() {
		return String.format("fixTimeDelta: '%s', queue: '%s'", fixTimeDelta, deque);
	}

	private class Pair {

		long data;
		long timestamp;

		public Pair(long data, long timestamp) {
			this.data = data;
			this.timestamp = timestamp;
		}

	}

}
